#include "worker.h"

// 生成随机字符（用于盐值）
char random_char() {
    const char* chars = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    return chars[rand() % 64];
}

// 生成$6$格式的盐值（SHA-512算法）
char* generate_salt_sha512(int rounds,char *salt,int salt_size) {
    char random_salt[17];  // 16字节随机盐 + 终止符

    // 生成16字节随机盐
    for (int i = 0; i < 16; i++) {
        random_salt[i] = random_char();
    }
    random_salt[16] = '\0';

    // 构建盐值字符串：$6$[rounds=N]$[salt]$
    if (rounds > 0) {
        snprintf(salt, salt_size, "$6$rounds=%d$%s$", rounds, random_salt);
    } else {
        snprintf(salt, salt_size, "$6$%s$", random_salt);  // 使用默认rounds
    }
    return salt;
}

// 加密密码（返回malloc分配的字符串，需手动free）
char* encrypt_password(const char* password, char *salt) {
    /* char* salt = generate_salt_sha512(rounds); */
    char* encrypted = crypt(password, salt);
    return strdup(encrypted);  // 复制结果，避免被后续调用覆盖
}

// 验证密码
int verify_password(const char* input, const char* stored_hash) {
    char* encrypted_input = crypt(input, stored_hash);
    /* printf("encrypted_input:%s\n",encrypted_input); */
    /* printf("stored_hash:%s\n",stored_hash); */
    return strcmp(encrypted_input, stored_hash) == 0;
}
/* int check_disconnect(ssize_t size,int *do_work_flag){ */
/*     if(size<=0){ */
/*         *do_work_flag=0; */
/*         return 1; */
/*     } */
/* return -1; */
/* } */
void * thread_func(void * arg){
    /* const char perfix[]="/root/wangpan/thread_pool/server/files"; */
    thread_pool_info_t * thread_pool_info=(thread_pool_info_t*)arg;
    while(1){
        /* printf("78979797978\n"); */
        //上锁
        pthread_mutex_lock(&thread_pool_info->mutex);
        while(thread_pool_info->exit_flag==0&&thread_pool_info->netfd_queue.size<=0){
            pthread_cond_wait(&thread_pool_info->cond,&thread_pool_info->mutex);
        }
        if(thread_pool_info->exit_flag==1){
            printf("the server is going to quit ,I as a thread have quited!!\n");
            pthread_mutex_unlock(&thread_pool_info->mutex);
            pthread_exit(NULL);
        }
        int netfd=get_head_netfd(&thread_pool_info->netfd_queue);
        printf("I as a thread got a netfd :%d\n",netfd);
        del_head_netfd(&thread_pool_info->netfd_queue);
        MYSQL* mysql=get_one_mysql_connect();
        pthread_mutex_unlock(&thread_pool_info->mutex);
        train_t train;
        int epfd=epoll_create(1);
        epoll_add(epfd,netfd);
        struct epoll_event epoll_res[1];
        srand(time(NULL));
        //判断是否登录成功
        int do_work_flag=0;
        //用户登录生成的盐值
        char salt[100]={0};
        //根据盐值生成的密文
        char ciphertext[300]={0};
        //客户端发送的用户名
        char user_name[100]={0};
        //客户端发送的密码
        char user_pwd[100]={0};
        //登录成功之后维护的用户名
        char current_user_name[100]={0};
        //登录成功之后存储的上一次登录时间
        char last_login_time[100]={0};
        //最近使用的十条指令
        char recent_cmd[300]={0};
        //登录成功之后维护的用户ID
        int  current_user_id=-1;
        //登录成功之后发送给客户端的信息,为"登录成功!+上一次登录时间"
        char login_msg[200]={0};
        //上传或者下载文件名
        char up_or_download_file_name[300];
        //这个用于判断每一个recvn的返回值如果小于等于0就检测到客户端退出然后断开连接
        /* ssize_t size=1; */
        //服务器文件的根目录地址
        /* const char perfix[]="/root/wangpan_project/wangpanv3/server/files"; */
        //用于存储类似cd ls命令跟的路径
        char temp_path[1024]={0};
        //用于mkdir.rmdir
        char temp_file_name[512]={0};
        //用于返回给客户端值的存储
        char temp_ret[1500]={0};
        while(!do_work_flag){
            epoll_wait(epfd,epoll_res,1,-1);
            if(epoll_res[0].data.fd==netfd){
                bzero(&train,sizeof(train));
                recvn(netfd,&train.type,sizeof(train.type));
                if(train.type==USER_REGISTER){
                    bzero(user_name,sizeof(user_name));
                    bzero(user_pwd,sizeof(user_pwd));
                    recvn(netfd,&train.length,sizeof(train.length));
                    recvn(netfd,train.data,train.length);

                    int flag=0;
                    char *token=strtok(train.data," ");
                    if (token != NULL) {
                        printf("第一个子字符串: %s\n", token);
                        strcpy(user_name,token);
                        // 以继续分割原字符串
                        token = strtok(NULL," ");
                        if (token != NULL) {
                            printf("第二个子字符串: %s\n", token);
                            strcpy(user_pwd,token);
                            flag=1;
                        }
                    }
                    if(flag){
                        bzero(&train,sizeof(train));
                        int ret=is_exist_username(mysql,user_name);
                        if(!ret){
                            bzero(salt,sizeof(salt));
                            bzero(ciphertext,sizeof(ciphertext));
                            generate_salt_sha512(0,salt,sizeof(salt));
                            printf("salt:%s\n",salt);
                            char * hash=encrypt_password(user_pwd,salt);
                            strcpy(ciphertext,hash);
                            ciphertext[strlen(ciphertext)]='\0';
                            printf("通过salt算出来的密文:%s\n",ciphertext);
                            user_info_t new_user;
                            strcpy(new_user.user_name, user_name);
                            strcpy(new_user.salt, salt);
                            strcpy(new_user.encrypted_password, ciphertext);
                            free(hash);
                            if(add_one_user(mysql,&new_user)){
                                log_info(mysql,new_user.id,"register",1,"register sucess");
                                train.type=REGISTER_SUCESS;
                                train.length=strlen("注册成功!");
                                strcpy(train.data,"注册成功!");
                            }
                        }else {
                            log_info(mysql,-1,"register",0,"user already exist!");
                            train.type=REGISTER_FAILD;
                            train.length=strlen("用户已存在!");
                            strcpy(train.data,"用户已存在!");
                        }
                    }else{
                        train.type=REGISTER_FAILD;
                        train.length=strlen("格式错误!");
                        strcpy(train.data,"格式错误!");
                    }
                    send(netfd,&train,sizeof(train.type)+sizeof(train.length)+train.length,0); 
                }else if(train.type==USER_LOGIN){
                    bzero(user_name,sizeof(user_name));
                    bzero(user_pwd,sizeof(user_pwd));
                    recvn(netfd,&train.length,sizeof(train.length));
                    recvn(netfd,train.data,train.length);
                    char *token=strtok(train.data," ");
                    int flag=0;
                    if (token != NULL) {
                        printf("第一个子字符串: %s\n", token);
                        strcpy(user_name,token);
                        // 以继续分割原字符串
                        token = strtok(NULL," ");
                        if (token != NULL) {
                            printf("第二个子字符串: %s\n", token);
                            strcpy(user_pwd,token);
                            flag=1;
                        }
                    }
                    if(flag){
                        bzero(&train,sizeof(train));
                        int ret=is_exist_username(mysql,user_name);
                        if(ret){
                            user_info_t user;
                            int user_id=get_user_id_by_user_name(mysql,user_name);
                            get_user_by_id(mysql,&user,user_id);
                            /* printf("user_pwd%s\n",user_pwd); */
                            /* printf("result:%d\n",verify_password(user_pwd,user.encrypted_password)); */
                            if(verify_password(user_pwd,user.encrypted_password)){
                                do_work_flag=1;
                                strcpy(current_user_name,user.user_name);
                                current_user_id=user_id;
                                train.type=LOGIN_SUCESS;
                                bzero(last_login_time,sizeof(last_login_time));
                                bzero(login_msg,sizeof(login_msg));
                                int ret=get_last_login_time(mysql,last_login_time,user_id);
                                strcat(login_msg,"登录成功!");
                                if(ret){
                                    strcat(login_msg," ");
                                    strcat(login_msg,"上一次登录时间:");
                                    strcat(login_msg,last_login_time);
                                }
                                train.length=strlen(login_msg);
                                strcpy(train.data,login_msg);
                                log_info(mysql,user_id,"login",1,"login sucess");
                            }else {
                                train.type=LOGIN_FAILD;
                                train.length=strlen("密码错误!");
                                strcpy(train.data,"密码错误!");
                                log_info(mysql,user_id,"login",0,"password wrong");
                            }
                        }else {
                            train.type=LOGIN_FAILD;
                            train.length=strlen("没有该用户!");
                            strcpy(train.data,"没有该用户!");
                            log_info(mysql,-1,"login",0,"no such user!");
                        }
                    }else{
                        train.type=LOGIN_FAILD;
                        train.length=strlen("格式错误!");
                        strcpy(train.data,"格式错误!");
                    }
                    send(netfd,&train,sizeof(train.type)+sizeof(train.length)+train.length,0);
                }else {
                    recvn(netfd,&train.length,sizeof(train.length));
                    recvn(netfd,train.data,train.length);
                    send_tips(netfd,"登录之后才能继续操作");
                }
            }
        }
        printf("---user_name:%s,user_id:%d user login sucess---\n",current_user_name,current_user_id);
        my_stack cur_stack;
        stack_init(&cur_stack);
        user_init(current_user_name,mysql,&cur_stack);
        //存储recvn的返回值如果为-1表示客户端退出
        int recvn_ret=0;
        while(do_work_flag){
            epoll_wait(epfd,epoll_res,1,-1);
            if(epoll_res[0].data.fd==netfd){
                bzero(&train,sizeof(train));
                recvn_ret=recvn(netfd,&train.type,sizeof(train.type));
                if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                if(train.type==CMD_CD){
                    // 调用cd方法,正确返回type=SEND_URL路径,不正确返回tip,type=SEND_TIP
                    recvn_ret= recvn(netfd,&train.length,sizeof(train.length));
                    if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                    recvn_ret=recvn(netfd,train.data,train.length);
                    if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                    bzero(temp_path,sizeof(temp_path));
                    bzero(temp_ret,sizeof(temp_ret));
                    strcpy(temp_path,train.data);
                    printf("--cd--%d,%s\n",train.length,temp_path);
                    int cd_ret=handle_cd(current_user_name,mysql,&cur_stack,temp_path,temp_ret);
                    if(cd_ret==0){
                        bzero(&train,sizeof(train));
                        train.type=SEND_URL;
                        train.length=strlen(temp_ret);
                        strcpy(train.data,temp_ret);
                        send(netfd,&train,sizeof(train.type)+sizeof(train.length)+train.length,0);
                        log_info(mysql,current_user_id,"cd",1,temp_path);
                    }else{
                        send_tips(netfd,"错误路径!");
                        log_info(mysql,current_user_id,"cd",0,temp_path);
                    }
                }else if(train.type==CMD_LS){
                    //调用ls方法,正确返回type=SEND_FILE_DIR 路径,不正确返回tip,type=SEND_TIP
                    recvn_ret=recvn(netfd,&train.length,sizeof(train.length));
                    if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                    recvn_ret=recvn(netfd,train.data,train.length);
                    if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                    bzero(temp_path,sizeof(temp_path));
                    bzero(temp_ret,sizeof(temp_ret));
                    strcpy(temp_path,train.data);
                    printf("--ls--%d,%s\n",train.length,temp_path);
                    int ls_ret=ls(mysql,&cur_stack,temp_ret,sizeof(temp_ret),temp_path,current_user_name);
                    if(ls_ret==0){
                        bzero(&train,sizeof(train));
                        train.type=SEND_FILE_DIR;
                        train.length=strlen(temp_ret);
                        strcpy(train.data,temp_ret);
                        printf("data:%s\n",train.data);
                        printf("length:%d\n",train.length);
                        /* printf("%s\n",train.data); */
                        send(netfd,&train,sizeof(train.type)+sizeof(train.length)+train.length,0);
                        log_info(mysql,current_user_id,"ls",1,temp_path);
                    }else{
                        send_tips(netfd,"错误路径!");
                        log_info(mysql,current_user_id,"ls",0,"wrong path!");
                    }
                }else if(train.type==CMD_PWD){
                    recvn_ret=recvn(netfd,&train.length,sizeof(train.length));
                    if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                    recvn_ret=recvn(netfd,train.data,train.length);
                    if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                    printf("--pwd--%d\n",train.length);
                    // 调用pwd方法,正确返回type=SEND_URL
                    bzero(temp_ret,sizeof(temp_ret));
                    pwd(mysql,&cur_stack,temp_ret,sizeof(temp_ret));
                    send_url(netfd,temp_ret);
                    log_info(mysql,current_user_id,"pwd",1,"");
                }else if(train.type==CMD_GETS){
                    bzero(up_or_download_file_name,sizeof(up_or_download_file_name));
                    recvn_ret=recvn(netfd,&train.length,sizeof(train.length));
                    if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                    recvn_ret=recvn(netfd,train.data,train.length);
                    if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                    strcpy(up_or_download_file_name,train.data);
                    printf("--gets--%d,%s\n",train.length,up_or_download_file_name);
                    user_t *user_dir=(user_t*)calloc(1,sizeof(user_t));
                    getsfile(current_user_id,netfd,mysql,user_dir,up_or_download_file_name,&cur_stack);
                    free(user_dir);
                }else if(train.type==CMD_PUTS){
                    bzero(up_or_download_file_name,sizeof(up_or_download_file_name));
                    recvn_ret=recvn(netfd,&train.length,sizeof(train.length));
                    if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                    recvn_ret=recvn(netfd,train.data,train.length);
                    if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                    strcpy(up_or_download_file_name,train.data);
                    printf("--puts--%d,%s\n",train.length,up_or_download_file_name);
                    user_t *user_dir=(user_t*)calloc(1,sizeof(user_t));
                    putsfile(current_user_id,netfd,mysql,user_dir,up_or_download_file_name,&cur_stack);
                    free(user_dir);
                }else if(train.type==CMD_REMOVE){
                    // 调用remove方法,正确返回tip type=SEND_TIP 路径,不正确返回tip,type=SEND_TIP
                    recvn_ret= recvn(netfd,&train.length,sizeof(train.length));
                    if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                    recvn_ret=recvn(netfd,train.data,train.length);
                    if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                    bzero(temp_file_name,sizeof(temp_file_name));
                    bzero(temp_ret,sizeof(temp_ret));
                    strcpy(temp_file_name,train.data);
                    printf("--remove--%d,%s\n",train.length,temp_file_name);
                    int remove_ret=remove_file(mysql,&cur_stack,temp_ret,sizeof(temp_ret),temp_file_name,current_user_name);
                    if(remove_ret==0){
                        send_tips(netfd,"删除成功!");
                        log_info(mysql,current_user_id,"remove",1,temp_file_name);
                    }else{
                        send_tips(netfd,temp_ret);
                        log_info(mysql,current_user_id,"remove",0,temp_file_name);
                    }
                }else if(train.type==CMD_MKDIR){
                    //调用mkdir方法,正确返回tip type=SEND_TIP 路径,不正确返回tip,type=SEND_TIP
                    recvn_ret=recvn(netfd,&train.length,sizeof(train.length));
                    if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                    recvn_ret=recvn(netfd,train.data,train.length);
                    if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                    bzero(temp_file_name,sizeof(temp_file_name));
                    strcpy(temp_file_name,train.data);
                    printf("--mkdir--%d,%s\n",train.length,temp_file_name);
                    int mkdir_ret=handle_mkdir(current_user_name,mysql,&cur_stack,temp_file_name);
                    if(mkdir_ret==0){
                        send_tips(netfd,"创建成功!");
                        log_info(mysql,current_user_id,"mkdir",1,temp_file_name);
                    }else if(mkdir_ret==1){
                        send_tips(netfd,"创建失败,不能有重复的目录!");
                        log_info(mysql,current_user_id,"mkdir",0,"can not has the same dir!");
                    }else if(mkdir_ret==-1){
                        send_tips(netfd,"创建失败,目录格式不对!");
                        log_info(mysql,current_user_id,"mkdir",0,"the dir is not right!");
                    }
                }else if(train.type==CMD_RMDIR){
                    // 调用rmdir方法,正确返回tip type=SEND_TIP 路径,不正确返回tip,type=SEND_TIP
                    recvn_ret=recvn(netfd,&train.length,sizeof(train.length));
                    if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                    recvn_ret=recvn(netfd,train.data,train.length);
                    if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                    bzero(temp_file_name,sizeof(temp_file_name));
                    strcpy(temp_file_name,train.data);
                    printf("--rmdir--%d,%s\n",train.length,temp_file_name);
                    int rmdir_ret=handle_rmdir(current_user_name,mysql,&cur_stack,temp_file_name);
                    if(rmdir_ret==0){
                        send_tips(netfd,"删除成功!");
                        log_info(mysql,current_user_id,"rmdir",1,temp_file_name);
                    }else{
                        send_tips(netfd,"删除失败,目录不为空!");
                        log_info(mysql,current_user_id,"rmdir",0,temp_file_name);
                    }
                }else  if(train.type==CMD_HISTORY){    
                    recvn_ret=recvn(netfd,&train.length,sizeof(train.length));
                    if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                    recvn_ret=recvn(netfd,train.data,train.length);
                    if(recvn_ret==-1){printf("netfd quit!%d\n",netfd);break;}
                    bzero(recent_cmd,sizeof(recent_cmd));
                    printf("--history--%d\n",train.length);
                    int ret=recent_use_cmd(mysql,recent_cmd,current_user_id);
                    if(ret){
                        send_tips(netfd,recent_cmd);
                    }else{
                        send_tips(netfd,"最近没有使用过任何命令!");
                    }
                    log_info(mysql,current_user_id,"history",1,recent_cmd);
                }
                else {
                    /* log_info(mysql,current_user_id,"cmd",0,"error cmd!"); */
                    send_tips(netfd,"命令行出错!!");
                }
            }
        }
        /* printf("%d\n",netfd); */
        close_mysql_connect(mysql);
        stack_destroy(&cur_stack);
        close(netfd);
    }
    return NULL;
}
//创建若干个工人线程
int create_worker(thread_pool_info_t *pthread_pool){                                                                                  
    for(int i=0;i<pthread_pool->worker_info.worker_num;i++){
        printf("id: %d thread has been created!\n",i+1);
        pthread_create(&pthread_pool->worker_info.worker_arr[i],NULL,thread_func,pthread_pool);
    }
    return 0;
}
